package com.ys.web.pay.service;

import cn.hutool.core.util.IdUtil;
import com.ys.base.BaseParam;
import com.ys.utils.base.http.McodeHandler;
import com.ys.utils.base.j2se.DateUtil;
import com.ys.utils.base.j2se.JsonUtil;
import com.ys.utils.base.j2se.Logger;
import com.ys.utils.base.j2se.StringHandler;
import com.ys.utils.pay.Result;
import com.ys.utils.redis.Redis;
import com.ys.utils.spring.config.SystemError;
import com.ys.web.pay.PayEnum;
import com.ys.web.pay.RedisKeyToYs;
import com.ys.web.pay.manager.PayManager;
import com.ys.web.pay.mapper.RedPacketMapper;
import com.ys.web.pay.model.BusiRedDealRecordCash;
import com.ys.web.pay.model.RedRecordCash;
import com.ys.web.sys.notice.service.NoticeService;
import com.ys.web.sys.notice.vo.SystemNoticeVo;
import com.ys.web.user.login.LoginInfo;
import com.ys.web.user.login.LoginService;
import com.ys.web.yinsheng.model.RequestData;
import com.ys.web.yinsheng.model.UserMerchant;
import com.ys.web.yinsheng.service.YinShengService;
import com.ys.web.yinsheng.util.ServiceEnum;
import com.ys.web.yinsheng.util.YinShengClient;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

@Service
@Slf4j
public class RedPacketService {
    @Value("${ys.default.head_img}")
    private String DEFAULT_IMG;

    // 红包过期时间 24小时
    private final int expireTime = 60 * 60 * 23;

    @Autowired
    private RedPacketMapper redPacketMapper;
    @Autowired
    private LoginService loginService;
    @Autowired
    private NoticeService noticeService;
    @Autowired
    private YinShengService yinShengService;

    public List<RedRecordCash> getUnGrad(Map<String, Object> map){return redPacketMapper.getUnGrad(map);}

    public List<Long> getGradByRedIds(long uid,List<Long> list){return redPacketMapper.getGradByRedIds(list, uid);}

    public List<Map<String,Object>> getRedListByUser(Map<String, Object> map){return redPacketMapper.getRedListByUser(map);}

    public RedRecordCash getRedRecordCashById(Long id){return redPacketMapper.getRedRecordCashById(id);}

    @Transactional
    public Result<Map<String, String>> giveRedPackage(String redType, String redAmount,
                                                      String redNum, String payType,
                                                      String giveUsers, String userId,
                                                      String content, String groupName,int payChannel) {
        Result<Map<String, String>> result;
        PayEnum.RedPackageType type = PayEnum.RedPackageType.getObjectByCode(redType);
        assert type != null;
        switch (type) {
            case Single:
                result = this.giveSingle(redAmount, redNum, payType, giveUsers, userId, content,payChannel);
                break;
            case GroupLuck:
                result = this.giveGroupLuck(redAmount, redNum, payType, userId, content, groupName,payChannel);
                break;
            case GroupNormal:
                result = this.giveGroupNormal(redAmount, redNum, payType, userId, content, groupName,payChannel);
                break;
            case GroupPersonal:
                result = this.giveGroupPersonal(redAmount, redNum, payType, giveUsers, userId, content, groupName,payChannel);
                break;
            default:
                result = Result.newFailure(-1, "红包类型不存在");
                break;
        }
        return result;
    }

    @Transactional
    public Result<Map<String, String>> giveSingle(String redAmount, String redNum, String payType, String giveUsers, String userId, String content,int payChannel) {
        Long redId;
        String messageId = IdUtil.randomUUID().toUpperCase();
        Map<String, String> map = new HashMap<>();
        if (Integer.parseInt(redNum ) != 1) {
            return Result.newFailure(-1, "红包数量错误");
        }
        if (payType.equals(PayEnum.payMentType.CHANGE.getCode()) || payType.equals(PayEnum.payMentType.BANK.getCode())) {
            // 修改用户账户
            Result<?> result = null;
            if(payChannel==3){
                result = PayManager.accountModifyZfb(Long.parseLong(userId), PayEnum.AccountFlowType.TYPE_RED_SEND, Long.parseLong(redAmount),giveUsers);
            }else if(payChannel==5){
                result = PayManager.accountModifyHjzf(Long.parseLong(userId), PayEnum.AccountFlowType.TYPE_RED_SEND, Long.parseLong(redAmount),giveUsers);
            }else{
                result = PayManager.accountModify(Long.parseLong(userId), PayEnum.AccountFlowType.TYPE_RED_SEND, Long.parseLong(redAmount),giveUsers,payChannel);
            }

            if (!result.success()) {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                return Result.newFailure(-1, result.getMessage());
            }
            // 保存红包信息
            redId = saveBusiRedRecord(Integer.parseInt(PayEnum.RedPackageStatus.Processing.getCode()),
                    PayEnum.RedPackageType.Single.getCode(),payType, redAmount, redNum, giveUsers, userId, content, null,messageId,payChannel);
            if (StringHandler.isEmpty(redId)) {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                return Result.newFailure(-1, "保存失败，事务回滚");
            }
            // 红包信息记入缓存
            saveSingleCache(redId+"", giveUsers, redAmount);
            // 返回红包id
            map.put("redId", redId+"");
            map.put("messageId", messageId);
        }else {
            return Result.newFailure(-1, "支付方式不支持");
        }
        return Result.newSuccess(map);
    }

    @Transactional
    public Result<Map<String, String>> giveGroupLuck(String redAmount, String redNum, String payType, String userId, String content, String groupName, int payChannel) {
        Long redId;
        String messageId = IdUtil.randomUUID().toUpperCase();
        Map<String, String> map = new HashMap<>();
        if (Integer.parseInt(redAmount)/Integer.parseInt(redNum) == 0) {
            return Result.newFailure(-1, "失败");
        }
        if (payType.equals(PayEnum.payMentType.CHANGE.getCode()) || payType.equals(PayEnum.payMentType.BANK.getCode())) {
            // 保存红包信息
            redId = saveBusiRedRecord(Integer.parseInt(PayEnum.RedPackageStatus.Processing.getCode()),
                    PayEnum.RedPackageType.GroupLuck.getCode(),payType, redAmount, redNum, null, userId, content, groupName,messageId,payChannel);
            // 修改用户账户
            Result<?> result = null;
            if(payChannel==3){
                result = PayManager.accountModifyZfb(Long.parseLong(userId), PayEnum.AccountFlowType.TYPE_RED_SEND, Long.parseLong(redAmount),"group");
            }else if(payChannel==5){
                result = PayManager.accountModifyHjzf(Long.parseLong(userId), PayEnum.AccountFlowType.TYPE_RED_SEND, Long.parseLong(redAmount),"group");
            }else{
                result = PayManager.accountModify(Long.parseLong(userId), PayEnum.AccountFlowType.TYPE_RED_SEND, Long.parseLong(redAmount),"group",payChannel);
            }

            if (!result.success()) {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                return Result.newFailure(-1, result.getMessage());
            }
            // 红包信息记入缓存
            saveGroupLuckCache(redId+"", redAmount, redNum, groupName);
            // 返回红包id
            map.put("redId", redId+"");
            map.put("messageId", messageId);
        } else {
            return Result.newFailure(-1, "支付方式不支持");
        }
        return Result.newSuccess(map);
    }

    @Transactional
    public Result<Map<String, String>> giveGroupNormal(String redAmount, String redNum, String payType, String userId, String content, String groupName, int payChannel) {
        Long redId;
        String messageId = IdUtil.randomUUID().toUpperCase();
        Map<String, String> map = new HashMap<>();
        if (payType.equals(PayEnum.payMentType.CHANGE.getCode()) || payType.equals(PayEnum.payMentType.BANK.getCode())) {
            // 保存红包信息
            redId = saveBusiRedRecord(Integer.parseInt(PayEnum.RedPackageStatus.Processing.getCode()),
                    PayEnum.RedPackageType.GroupNormal.getCode(),payType, redAmount, redNum, null, userId, content, groupName,messageId,payChannel);
            // 修改用户账户
            Result<?> result = null;
            if(payChannel==3){
                result =  PayManager.accountModifyZfb(Long.parseLong(userId), PayEnum.AccountFlowType.TYPE_RED_SEND,
                        Long.parseLong(redAmount)*Long.parseLong(redNum),"group");
            }else if(payChannel==5){
                result =  PayManager.accountModifyHjzf(Long.parseLong(userId), PayEnum.AccountFlowType.TYPE_RED_SEND,
                        Long.parseLong(redAmount)*Long.parseLong(redNum),"group");
            }else{
                result = PayManager.accountModify(Long.parseLong(userId), PayEnum.AccountFlowType.TYPE_RED_SEND,
                        Long.parseLong(redAmount)*Long.parseLong(redNum),"group",payChannel);
            }

            if (!result.success()) {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                return Result.newFailure(-1, result.getMessage());
            }
            // 红包信息记入缓存
            saveGroupNormalCache(redId+"", redAmount, redNum, groupName);
            // 返回红包id
            map.put("redId", redId+"");
            map.put("messageId", messageId);
        }else {
            return Result.newFailure(-1, "支付方式不支持");
        }
        return Result.newSuccess(map);
    }

    @Transactional
    public Result<Map<String, String>> giveGroupPersonal(String redAmount, String redNum, String payType, String giveUsers, String userId, String content, String groupName, int payChannel) {
        Long redId;
        String messageId = IdUtil.randomUUID().toUpperCase();
        Map<String, String> map = new HashMap<>();
        if (Integer.parseInt(redAmount)/Integer.parseInt(redNum) == 0) {
            return Result.newFailure(-1, "失败");
        }
        if (payType.equals(PayEnum.payMentType.CHANGE.getCode()) || payType.equals(PayEnum.payMentType.BANK.getCode())) {
            // 保存红包信息
            redId = saveBusiRedRecord(Integer.parseInt(PayEnum.RedPackageStatus.Processing.getCode()),
                    PayEnum.RedPackageType.GroupPersonal.getCode(),payType, redAmount, redNum, giveUsers, userId, content, groupName,messageId,payChannel);
            // 修改用户账户
            Result<?> result =null;
            if(payChannel==3){
                result = PayManager.accountModifyZfb(Long.parseLong(userId), PayEnum.AccountFlowType.TYPE_RED_SEND,
                        Long.parseLong(redAmount),giveUsers);
            }else if(payChannel==5){
                result = PayManager.accountModifyHjzf(Long.parseLong(userId), PayEnum.AccountFlowType.TYPE_RED_SEND,
                        Long.parseLong(redAmount),giveUsers);
            }else{
                // 修改用户账户
                result = PayManager.accountModify(Long.parseLong(userId), PayEnum.AccountFlowType.TYPE_RED_SEND,
                        Long.parseLong(redAmount),giveUsers,payChannel);
            }

            if (!result.success()) {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                return Result.newFailure(-1, result.getMessage());
            }
            // 红包信息记入缓存
            saveGroupPersonalCache(redId+"", redAmount, redNum, giveUsers, groupName);
            // 返回红包id
            map.put("redId", redId+"");
            map.put("messageId", messageId);
        }else {
            return Result.newFailure(-1, "支付方式不支持");
        }
        return Result.newSuccess(map);
    }

    private Long saveBusiRedRecord(int status, String redType,String payType, String redAmount, String redNum, String giveUsers,
                                   String userId, String content, String groupName,String messageId,int payChannel) {
        RedRecordCash redRecord = new RedRecordCash();
        redRecord.setUserId(Long.parseLong(userId));
        redRecord.setType(Integer.parseInt(redType));
        redRecord.setPayType(Integer.parseInt(payType));
        redRecord.setRedStatus(status);
        redRecord.setAmount(Long.parseLong(redAmount));
        redRecord.setSize(Integer.parseInt(redNum));
        redRecord.setDateKey(StringHandler.getInt(com.ys.utils.base.j2se.DateUtil.getYYMMDD()));
        redRecord.setMonthKey(StringHandler.getInt(com.ys.utils.base.j2se.DateUtil.getYYMM()));
        redRecord.setListUserId(giveUsers);
        redRecord.setContent(content);
        redRecord.setGroupName(groupName);
        redRecord.setGp(StringHandler.isEmpty(groupName)?1:2);
        redRecord.setMessageId(messageId);
        redRecord.payChannel=payChannel;
        try{
            redPacketMapper.saveBusiRedRecord(redRecord);
        }catch (Exception e){
            if(StringHandler.isPKConflict(e.getCause())){
                redPacketMapper.saveBusiRedRecord(redRecord);
            }
        }
        return redRecord.getId();
    }

    public Result<?> saveSingleCache(String redId, String giveUsers, String redAmount) {
        String key = null;
        try {
            Redis.str.set(RedisKeyToYs.REDIS_RED_PREFIX + redId, String.valueOf(redId), expireTime);
            key = RedisKeyToYs.REDIS_RED_SINGLE_PREFIX + redId + "-" + giveUsers;
            Redis.str.set(key, redAmount);
        } catch (Exception e) {
            e.printStackTrace();
            clearCache(RedisKeyToYs.REDIS_RED_PREFIX + redId, key, null, null);
            return Result.newFailure(-1, "缓存保存异常");
        }
        return Result.newSuccess();
    }

    public Result<?> saveGroupPersonalCache(String redId, String redAmount, String redNum, String giveUsers, String groupName) {
        String redKey = null;
        String redUserKey = null;
        String redUserDisKey = null;
        try {
            Redis.str.set(RedisKeyToYs.REDIS_RED_PREFIX + redId, groupName, expireTime);
            // 红包信息记入缓存
            List<Integer> redPackageList = divideRedPackage(Integer.parseInt(redAmount), Integer.parseInt(redNum));
            // 剩余红包缓存
            redKey = RedisKeyToYs.REDIS_RED_GROUPPERSONAL_PREFIX + redId;
//            if(!Redis.key.exists(redKey)){

            Redis.list.pushList(redKey, redPackageList.stream().map(StringHandler::getString).collect(Collectors.toList()));
//            }
            // 已抢红包用户缓存
//            redUserKey = RedisKeyToYs.REDIS_RED_USER_GROUPPERSONAL_PREFIX + redId;
//            Redis.list.pushList(redUserKey, new ArrayList<String>());
            // 分配红包用户缓存
            redUserDisKey = RedisKeyToYs.REDIS_RED_USER_GROUPPERSONAL_DISTRIBUTE_PREFIX + redId;
            Redis.list.pushList(redUserDisKey, getUserList(giveUsers));
        } catch (Exception e) {
            e.printStackTrace();
            clearCache(RedisKeyToYs.REDIS_RED_PREFIX + redId, redKey, redUserKey, redUserDisKey);
            return Result.newFailure(-1, "缓存保存异常");
        }
        return Result.newSuccess();
    }

    public Result<?> saveGroupLuckCache(String redId, String redAmount, String redNum, String groupName) {
        String redKey = null;
        String redUserKey = null;
        try {
            Redis.str.set(RedisKeyToYs.REDIS_RED_PREFIX + redId, groupName, expireTime);
            // 红包信息记入缓存
            List<Integer> redPackageList = divideRedPackage(Integer.parseInt(redAmount), Integer.parseInt(redNum));
            // 剩余红包缓存
            redKey = RedisKeyToYs.REDIS_RED_GROUPLUCK_PREFIX + redId;
//            if(!Redis.key.exists(redKey)){

            Redis.list.pushList(redKey, redPackageList.stream().map(StringHandler::getString).collect(Collectors.toList()));
//            }
            // 已抢红包用户缓存
//            redUserKey = RedisKeyToYs.REDIS_RED_USER_GROUPLUCK_PREFIX + redId;
//            Redis.list.pushList(redUserKey, new ArrayList<String>());
        } catch (Exception e) {
            e.printStackTrace();
            clearCache(RedisKeyToYs.REDIS_RED_PREFIX + redId, redKey, redUserKey, null);
            return Result.newFailure(-1, "缓存保存异常");
        }
        return Result.newSuccess();
    }

    public Result<?> saveGroupNormalCache(String redId, String redAmount, String redNum, String groupName) {
        String redKey = null;
        String redUserKey = null;
        try {
            Redis.str.set(RedisKeyToYs.REDIS_RED_PREFIX + redId, groupName, expireTime);
            // 红包信息记入缓存
            List<Integer> redPackageList = new ArrayList<>();
            for (int i = 0; i < Integer.parseInt(redNum); i++) {
                redPackageList.add(Integer.parseInt(redAmount));
            }
            // 剩余红包缓存
            redKey = RedisKeyToYs.REDIS_RED_GROUPNORMAL_PREFIX + redId;

//            if(!Redis.key.exists(redKey)){

            Redis.list.pushList(redKey, redPackageList.stream().map(StringHandler::getString).collect(Collectors.toList()));
//            }
            // 已抢红包用户缓存
//            redUserKey = RedisKeyToYs.REDIS_RED_USER_GROUPNORMAL_PREFIX + redId;
//            Redis.list.pushList(redUserKey, new ArrayList<String>());
        } catch (Exception e) {
            e.printStackTrace();
            clearCache(RedisKeyToYs.REDIS_RED_PREFIX + redId, redKey, redUserKey, null);
            return Result.newFailure(-1, "缓存保存异常");
        }
        return Result.newSuccess();
    }


    public  List<Integer> divideRedPackage(Integer totalAmount, Integer totalPeopleNum){
        List<Integer> amountList = new ArrayList<>();
        Integer restAmount = totalAmount;
        Integer restPeopleNum = totalPeopleNum;
        Random random = new Random();
        for(int i = 0; i < totalPeopleNum - 1; i++) {
            //随机范围：[1，剩余人均金额的两倍)，左闭右开
            int amount = random.nextInt(restAmount / restPeopleNum * 2 - 1) + 1;
            restAmount -= amount;
            restPeopleNum --;
            amountList.add(amount);
        }
        amountList.add(restAmount);
        return amountList;
    }

    private List<String> getUserList(String giveUsers) {
        String[] array = giveUsers.split(",");
        return new ArrayList<>(Arrays.asList(array));
    }

    // 红包发完、退回清除红包缓存
    private void clearCache(String... keys) {
        for (String key : keys) {
            if (StringHandler.isNotEmpty(key)) {
                Redis.key.del(key);
            }
        }
    }

    @Transactional
    public Result<Map<String, String>> getRedPackage(String redId, RedRecordCash redRecord, String userId, UserMerchant inUser,int payChannel) {
        String amount = "";// 抢红包金额
        String key = "";//红包Key
        // 抢红包
        String redType = String.valueOf(redRecord.getType());// 红包类型
        if (redType.equals(PayEnum.RedPackageType.Single.getCode())) {
            key = RedisKeyToYs.REDIS_RED_SINGLE_PREFIX + redId + "-" + userId;
            amount = String.valueOf(redRecord.getAmount());

            // 修改红包状态
            Result<RedRecordCash> redRecordResult = updateBusiRedRecord(redRecord);
            if (!redRecordResult.success()) {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                return Result.newFailure(-1, redRecordResult.getMessage());
            }
            Result<?> result = null;
            if(payChannel==3){
                result = PayManager.accountModifyZfb(Long.parseLong(userId), PayEnum.AccountFlowType.TYPE_RED_RECV,
                        Long.parseLong(amount), StringHandler.getString(redRecord.getUserId()));
            }else if(payChannel==5){
                result = PayManager.accountModifyHjzf(Long.parseLong(userId), PayEnum.AccountFlowType.TYPE_RED_RECV,
                        Long.parseLong(amount), StringHandler.getString(redRecord.getUserId()));
            }else{
                result = PayManager.accountModify(Long.parseLong(userId), PayEnum.AccountFlowType.TYPE_RED_RECV,
                        Long.parseLong(amount), StringHandler.getString(redRecord.getUserId()),payChannel);
            }
            // 修改用户账户

            if (!result.success()) {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                return Result.newFailure(-1, result.getMessage());
            }
            // 保存抢红包记录
            saveBusiRedDealRecord(redId, amount, userId, redRecord.getUserId(), redRecord.getGroupName());
            // 清除缓存
            String redKey = RedisKeyToYs.REDIS_RED_PREFIX + redId;
            clearCache(redKey, key, null, null);
        }else if (redType.equals(PayEnum.RedPackageType.GroupLuck.getCode())) {
            key = RedisKeyToYs.REDIS_RED_GROUPLUCK_PREFIX + redId;
            String redUserKey = RedisKeyToYs.REDIS_RED_USER_GROUPLUCK_PREFIX + redId;
            amount = Redis.list.lPop(key);
            if(StringHandler.isEmpty(amount)){
                // 修改红包状态
                updateBusiRedRecord(redRecord);
                // 清除缓存
                String redKey = RedisKeyToYs.REDIS_RED_PREFIX + redId;
                clearCache(redKey, key, redUserKey, null);
                SystemError.wrapBs("500","红包已领完");
            }
            // 修改用户账户
            Result<?> result = null;
            if(payChannel==3){
                result = PayManager.accountModifyZfb(Long.parseLong(userId), PayEnum.AccountFlowType.TYPE_RED_RECV,
                        Long.parseLong(amount),StringHandler.getString(redRecord.getUserId()));
            }else if(payChannel==5){
                result = PayManager.accountModifyHjzf(Long.parseLong(userId), PayEnum.AccountFlowType.TYPE_RED_RECV,
                        Long.parseLong(amount),StringHandler.getString(redRecord.getUserId()));
            }else{
                result = PayManager.accountModify(Long.parseLong(userId), PayEnum.AccountFlowType.TYPE_RED_RECV,
                        Long.parseLong(amount),StringHandler.getString(redRecord.getUserId()),payChannel);
            }
            if (!result.success()) {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                return Result.newFailure(-1, result.getMessage());
            }
            if(Redis.list.size(key)==0){
                updateBusiRedRecord(redRecord);
                // 清除缓存
                String redKey = RedisKeyToYs.REDIS_RED_PREFIX + redId;
                clearCache(redKey, key, redUserKey, null);
            }else {
                // 已抢红包缓存
                Redis.list.rPush(redUserKey, userId);
            }
            // 保存抢红包记录
            saveBusiRedDealRecord(redId, amount, userId, redRecord.getUserId(), redRecord.getGroupName());
        }else if (redType.equals(PayEnum.RedPackageType.GroupNormal.getCode())) {
            key = RedisKeyToYs.REDIS_RED_GROUPNORMAL_PREFIX + redId;
            String redUserKey = RedisKeyToYs.REDIS_RED_USER_GROUPNORMAL_PREFIX + redId;
            amount = Redis.list.lPop(key);
            if(StringHandler.isEmpty(amount)){
                // 修改红包状态
                updateBusiRedRecord(redRecord);
                // 清除缓存
                String redKey = RedisKeyToYs.REDIS_RED_PREFIX + redId;
                clearCache(redKey, key, redUserKey, null);
                SystemError.wrapBs("500","红包已领完");
            }
            // 修改用户账户
            Result<?> result = null;
            if(payChannel==3){
                // 修改用户账户
                result = PayManager.accountModifyZfb(Long.parseLong(userId), PayEnum.AccountFlowType.TYPE_RED_RECV,
                        Long.parseLong(amount),StringHandler.getString(redRecord.getUserId()));
            }else if(payChannel==5){
                result = PayManager.accountModifyHjzf(Long.parseLong(userId), PayEnum.AccountFlowType.TYPE_RED_RECV,
                        Long.parseLong(amount),StringHandler.getString(redRecord.getUserId()));
            }else{
                // 修改用户账户
                result = PayManager.accountModify(Long.parseLong(userId), PayEnum.AccountFlowType.TYPE_RED_RECV,
                        Long.parseLong(amount),StringHandler.getString(redRecord.getUserId()),payChannel);
            }

            if (!result.success()) {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                return Result.newFailure(-1, result.getMessage());
            }
            if(Redis.list.size(key)==0){
                updateBusiRedRecord(redRecord);
                // 清除缓存
                String redKey = RedisKeyToYs.REDIS_RED_PREFIX + redId;
                clearCache(redKey, key, redUserKey, null);
            }else {
                // 已抢红包缓存
                Redis.list.rPush(redUserKey, userId);
            }
            // 保存抢红包记录
            saveBusiRedDealRecord(redId, amount, userId, redRecord.getUserId(), redRecord.getGroupName());
        }else if (redType.equals(PayEnum.RedPackageType.GroupPersonal.getCode())) {
            key = RedisKeyToYs.REDIS_RED_GROUPPERSONAL_PREFIX + redId;
            String redUserKey = RedisKeyToYs.REDIS_RED_USER_GROUPPERSONAL_PREFIX + redId;
            String redUserDisKey = RedisKeyToYs.REDIS_RED_USER_GROUPPERSONAL_DISTRIBUTE_PREFIX + redId;
            amount = Redis.list.lPop(key);
            if(StringHandler.isEmpty(amount)){
                // 修改红包状态
                updateBusiRedRecord(redRecord);
                // 清除缓存
                String redKey = RedisKeyToYs.REDIS_RED_PREFIX + redId;
                clearCache(redKey, key, redUserKey, redUserDisKey);
                SystemError.wrapBs("500","红包已领完");
            }
            // 修改用户账户
            Result<?> result = null;
            if(payChannel==3){
                // 修改用户账户
                result = PayManager.accountModifyZfb(Long.parseLong(userId), PayEnum.AccountFlowType.TYPE_RED_RECV,
                        Long.parseLong(amount),StringHandler.getString(redRecord.getUserId()));
            }else if(payChannel==5){
                result = PayManager.accountModifyHjzf(Long.parseLong(userId), PayEnum.AccountFlowType.TYPE_RED_RECV,
                        Long.parseLong(amount),StringHandler.getString(redRecord.getUserId()));
            }else {
                // 修改用户账户
                result = PayManager.accountModify(Long.parseLong(userId), PayEnum.AccountFlowType.TYPE_RED_RECV,
                        Long.parseLong(amount),StringHandler.getString(redRecord.getUserId()),payChannel);
            }

            if (!result.success()) {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                return Result.newFailure(-1, result.getMessage());
            }
            if(Redis.list.size(key)==0){
                updateBusiRedRecord(redRecord);
                // 清除缓存
                String redKey = RedisKeyToYs.REDIS_RED_PREFIX + redId;
                clearCache(redKey, key, redUserKey, null);
            }else {
                // 已抢红包缓存
                Redis.list.rPush(redUserKey, userId);
            }
            // 保存抢红包记录
            saveBusiRedDealRecord(redId, amount, userId, redRecord.getUserId(), redRecord.getGroupName());
        }
        Map<String, String> map = new HashMap<>();
        map.put("amount", amount);
        if(payChannel<3){
            //自己抢自己不做转账处理
            if (inUser.uid != redRecord.getUserId()) {
                // 银盛内部转账逻辑将抢红包金额转入抢红包用户钱包
                //查询发送人钱包信息 redRecord.getUserId()
                UserMerchant outUser = yinShengService.userMerchant(redRecord.getUserId() + "");
                // 组装业务参数
                Map<String, Object> requestMap1 = new HashMap<>();
                String requestNo = BaseParam.getOrderSN();
                requestMap1.put("requestNo", requestNo);
                requestMap1.put("payeeMerchantNo", inUser.merchantNo);//收款方银盛商户号
                requestMap1.put("payerMerchantNo", outUser.merchantNo);//付款方银盛商户号
                requestMap1.put("transferType", "C2C");//转账类型 P2B-平台转商户 P2C-平台转用户 B2P-商户转平台 B2B-商户转商户 B2C-商户转用户 C2C-用户转用户 A2A-资金归集
                requestMap1.put("orderDesc", "转账");//商品名称/订单标题
                requestMap1.put("amount", StringHandler.fenToYuan(amount));//提现金额，单位：元
                requestMap1.put("remark", "R-转账");
                RequestData requestData = new RequestData(requestMap1);
                YinShengClient yinShengClient = new YinShengClient(ServiceEnum.TRANSFER_INNER);
                String callback1 = yinShengClient.requestStrApi(requestData);
                Map<String, Object> obj1 = JsonUtil.jsonToBean(callback1, Map.class);
                if (!obj1.get("code").equals("SYS000")) {
                    log.error("R-转账失败:" + StringHandler.getString(obj1.get("msg")),JsonUtil.toJson(redRecord), new Exception());
                    // 失败回滚事务，并且修复Redis数据:
                    Redis.list.lpush(key, amount);
                    SystemError.wrapBs("500", "转账失败");
                } else {
                    if (StringHandler.isNotEmpty(obj1.get("bizResponseJson"))) {
                        Map<String, Object> bizResponseJson1 = JsonUtil.jsonNullToBean(JsonUtil.toJson(obj1.get("bizResponseJson")), Map.class);
                        if (!bizResponseJson1.get("subCode").equals("COM000")) {
                            Redis.list.lpush(key, amount);
                            log.error("R-转账:" + StringHandler.getString(obj1.get("msg")) + "_" + StringHandler.getString(bizResponseJson1.get("subMsg")),JsonUtil.toJson(redRecord), new Exception());
                            SystemError.wrapBs("500", "转账失败");
                        }
                    } else {
                        Redis.list.lpush(key, amount);
                        log.error("R-转账:" + StringHandler.getString(obj1.get("msg")),JsonUtil.toJson(redRecord), new Exception());
                        SystemError.wrapBs("500", "转账失败");
                    }
                }
            }
        }
        return Result.newSuccess(map);
    }


    private String luckUser(List<LoginInfo> userList) {
        long max = 0L;
        String userId = "0";
        for (LoginInfo user : userList) {
            if (BigDecimal.valueOf(Long.parseLong(user.getAmount())).compareTo(BigDecimal.valueOf(max)) > 0) {
                max = Long.parseLong(user.getAmount());
                userId = user.getId();
            }
        }
        return userId;
    }

    private Result<RedRecordCash> updateBusiRedRecord(RedRecordCash redRecord) {
        redRecord.setRedStatus(Integer.parseInt(PayEnum.RedPackageStatus.Complete.getCode()));
        return redPacketMapper.updateRedRecordCash(redRecord)==1 ? Result.newSuccess(redRecord) : Result.newFailure(-1, "失败");
    }

    private void saveBusiRedDealRecord(String redId, String redAmount, String userId, Long _userId, String groupName) {
        BusiRedDealRecordCash redDealRecord = new BusiRedDealRecordCash();
        redDealRecord.setRedId(Long.parseLong(redId));
        redDealRecord.setUserId(Long.parseLong(userId));
        redDealRecord.setAmount(Long.parseLong(redAmount));
        redDealRecord.setRedUserId(_userId);
        redDealRecord.setGroupName(groupName);
        redPacketMapper.saveBusiRedDealRecordCash(redDealRecord);
    }

    public void redGoBack() {
        Logger.info("========================红包定时处理开始========================");
        Date addTime = com.ys.utils.base.j2se.DateUtil.getHourAfterTime(-23);
        Map<String, Object> map = new HashMap<>();
        map.put("EQ_status", PayEnum.RedPackageStatus.Processing.getCode());
        map.put("addTime", com.ys.utils.base.j2se.DateUtil.getDate(addTime,"yyyy-MM-dd HH:mm:ss"));
        List<RedRecordCash> redRecords = redPacketMapper.getRedRecordCashList(map);
        if (StringHandler.isEmpty(redRecords)) {// 没有进行中红包
            Logger.info("========================没有进行中红包========================");
            return;
        }
        for (RedRecordCash redRecord : redRecords) {
            Long redId = redRecord.getId();
//            if (redRecord.getRawAddTime().after(addTime)) {// 红包未过期
//                log.info("========================红包未过期========================");
//                continue;
//            }
//            if (Redis.key.exists(RedisKeyToYs.REDIS_RED_PREFIX + redId)) {// 红包未过期
//                log.info("========================红包未过期========================");
//                continue;
//            }
            Logger.info("========================红包过期处理========================" + redId);
            // 红包过期，退回红包
            PayEnum.RedPackageType type = PayEnum.RedPackageType.getObjectByCode(String.valueOf(redRecord.getType()));
            switch (type) {
                case Single:
                    this.goBackSingle(redRecord);
                    break;
                case GroupLuck:
                    this.goBackGroupLuck(redRecord);
                    break;
                case GroupNormal:
                    this.goBackGroupNormal(redRecord);
                    break;
                case GroupPersonal:
                    this.goBackGroupPersonal(redRecord);
                    break;
                default:
                    break;
            }
        }
        Logger.info("========================红包定时处理结束========================");
    }

    @Transactional
    public void goBackSingle(RedRecordCash redRecord) {
        // 更新红包状态为过期
        redRecord.setRedStatus(Integer.parseInt(PayEnum.RedPackageStatus.Expire.getCode()));
        int i = redPacketMapper.updateRedRecordCash(redRecord);
        if (i!=1) {
            return;
        }
        Result<?> result = null;
        if(redRecord.payChannel==3){
            // 修改用户账户
            result = PayManager.accountModifyZfb(redRecord.getUserId(), PayEnum.AccountFlowType.TYPE_RED_EXPR,
                    redRecord.getAmount(),StringHandler.getString(redRecord.getListUserId()));
        }else if(redRecord.payChannel==5){
            result = PayManager.accountModifyHjzf(redRecord.getUserId(), PayEnum.AccountFlowType.TYPE_RED_EXPR,
                    redRecord.getAmount(),StringHandler.getString(redRecord.getListUserId()));
        }else{
            // 修改用户账户
            result = PayManager.accountModify(redRecord.getUserId(), PayEnum.AccountFlowType.TYPE_RED_EXPR,
                    redRecord.getAmount(),StringHandler.getString(redRecord.getListUserId()),redRecord.payChannel);
        }

        if (!result.success()) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return;
        }
        String key = RedisKeyToYs.REDIS_RED_SINGLE_PREFIX + redRecord.getId() + "-" + redRecord.getListUserId();
        clearCache(null, key, null,null);
        // TODO 红包退还推送
        noticeService.sendOverdueBackNotice(SystemNoticeVo
                .build("红包退还通知",String.format("<p>您有一笔红包已过期退还</p>" +
                                "<p>退还金额：%s元</p>" +
                                "<p>发红包时间：%s</p>",
                        StringHandler.fenToYuan(StringHandler.getString(redRecord.getAmount())),
                        DateUtil.getDate(redRecord.getRawAddTime(),"yyyy-MM-dd HH:mm:ss")),
                        redRecord.getUserId()));
    }

    @Transactional
    public void goBackGroupLuck(RedRecordCash redRecord) {
        // 更新红包状态为过期
        redRecord.setRedStatus(Integer.parseInt(PayEnum.RedPackageStatus.Expire.getCode()));
        int i = redPacketMapper.updateRedRecordCash(redRecord);
        if (i!=1) {
            return;
        }
        // 计算未抢红包金额，返还账户
        long modifyAmount = 0; // 返回金额
        long amount = redRecord.getAmount(); // 红包总金额
        long sumAmount = redPacketMapper.getSumAmount(redRecord.getId()); // 已发金额
        modifyAmount = amount - sumAmount;
        if (modifyAmount <= 0) {
            return;
        }
        // 修改用户账户
        Result<?> result = null;
        if(redRecord.payChannel==3){
            result = PayManager.accountModifyZfb(redRecord.getUserId(), PayEnum.AccountFlowType.TYPE_RED_EXPR,
                    modifyAmount,"group");
        }else if(redRecord.payChannel==5){
            result = PayManager.accountModifyHjzf(redRecord.getUserId(), PayEnum.AccountFlowType.TYPE_RED_EXPR,
                    modifyAmount,"group");
        }else{
            result = PayManager.accountModify(redRecord.getUserId(), PayEnum.AccountFlowType.TYPE_RED_EXPR,
                    modifyAmount,"group",redRecord.payChannel);
        }
        if (!result.success()) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return;
        }
        String key = RedisKeyToYs.REDIS_RED_GROUPLUCK_PREFIX + redRecord.getId();
        String redUserKey = RedisKeyToYs.REDIS_RED_USER_GROUPLUCK_PREFIX + redRecord.getId();
        String redKey = RedisKeyToYs.REDIS_RED_PREFIX + redRecord.getId();
        clearCache(redKey, key, redUserKey,null);
        // TODO 红包退还推送
        noticeService.sendOverdueBackNotice(SystemNoticeVo
                .build("红包退还通知",String.format("<p>您有一笔红包已过期退还</p>" +
                                "<p>退还金额：%s元</p>" +
                                "<p>发红包时间：%s</p>",
                        StringHandler.fenToYuan(StringHandler.getString(modifyAmount)),
                        DateUtil.getDate(redRecord.getRawAddTime(),"yyyy-MM-dd HH:mm:ss")),
                        redRecord.getUserId()));
    }

    @Transactional
    public void goBackGroupNormal(RedRecordCash redRecord) {
        // 更新红包状态为过期
        redRecord.setRedStatus(Integer.parseInt(PayEnum.RedPackageStatus.Expire.getCode()));
        int i = redPacketMapper.updateRedRecordCash(redRecord);
        if (i!=1) {
            return;
        }
        // 计算未抢红包金额，返还账户
        long modifyAmount = 0; // 返回金额
        long amount = redRecord.getAmount() * redRecord.getSize(); // 红包总金额
        long sumAmount = redPacketMapper.getSumAmount(redRecord.getId()); // 已发金额
        modifyAmount = amount - sumAmount;
        if (modifyAmount <= 0) {
            return;
        }
        // 修改用户账户
        Result<?> result = null;
        if(redRecord.payChannel==3){
            result = PayManager.accountModifyZfb(redRecord.getUserId(), PayEnum.AccountFlowType.TYPE_RED_EXPR,
                    modifyAmount,"group");
        }else if(redRecord.payChannel==5){
            result = PayManager.accountModifyHjzf(redRecord.getUserId(), PayEnum.AccountFlowType.TYPE_RED_EXPR,
                    modifyAmount,"group");
        }else{
            result = PayManager.accountModify(redRecord.getUserId(), PayEnum.AccountFlowType.TYPE_RED_EXPR,
                    modifyAmount,"group",redRecord.payChannel);
        }

        if (!result.success()) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return;
        }
        String key = RedisKeyToYs.REDIS_RED_GROUPNORMAL_PREFIX + redRecord.getId();
        String redUserKey = RedisKeyToYs.REDIS_RED_USER_GROUPNORMAL_PREFIX + redRecord.getId();
        String redKey = RedisKeyToYs.REDIS_RED_PREFIX + redRecord.getId();
        clearCache(redKey, key, redUserKey,null);
        // TODO 红包退还推送
        noticeService.sendOverdueBackNotice(SystemNoticeVo
                .build("红包退还通知",String.format("<p>您有一笔红包已过期退还</p>" +
                                "<p>退还金额：%s元</p>" +
                                "<p>发红包时间：%s</p>",
                        StringHandler.fenToYuan(StringHandler.getString(modifyAmount)),
                        DateUtil.getDate(redRecord.getRawAddTime(),"yyyy-MM-dd HH:mm:ss")),
                        redRecord.getUserId()));
    }

    @Transactional
    public void goBackGroupPersonal(RedRecordCash redRecord) {
        // 更新红包状态为过期
        redRecord.setRedStatus(Integer.parseInt(PayEnum.RedPackageStatus.Expire.getCode()));
        int i = redPacketMapper.updateRedRecordCash(redRecord);
        if (i!=1) {
            return;
        }
        // 计算未抢红包金额，返还账户
        long modifyAmount = 0; // 返回金额
        long amount = redRecord.getAmount(); // 红包总金额
        long sumAmount = redPacketMapper.getSumAmount(redRecord.getId()); // 已发金额
        modifyAmount = amount - sumAmount;
        if (modifyAmount <= 0) {
            return;
        }
        // 修改用户账户
        Result<?> result = null;
        if(redRecord.payChannel==3){
            // 修改用户账户
            result = PayManager.accountModifyZfb(redRecord.getUserId(), PayEnum.AccountFlowType.TYPE_RED_EXPR,
                    modifyAmount,redRecord.getListUserId());
        }else if(redRecord.payChannel==5){
            result = PayManager.accountModifyHjzf(redRecord.getUserId(), PayEnum.AccountFlowType.TYPE_RED_EXPR,
                    modifyAmount,redRecord.getListUserId());
        }else{
            // 修改用户账户
            result = PayManager.accountModify(redRecord.getUserId(), PayEnum.AccountFlowType.TYPE_RED_EXPR,
                    modifyAmount,redRecord.getListUserId(),redRecord.payChannel);
        }

        if (!result.success()) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return;
        }
        String key = RedisKeyToYs.REDIS_RED_GROUPPERSONAL_PREFIX + redRecord.getId();
        String redUserKey = RedisKeyToYs.REDIS_RED_USER_GROUPPERSONAL_PREFIX + redRecord.getId();
        String redUserDisKey = RedisKeyToYs.REDIS_RED_USER_GROUPPERSONAL_DISTRIBUTE_PREFIX + redRecord.getId();
        clearCache(null, key, redUserKey,redUserDisKey);
        // TODO 红包退还推送
        noticeService.sendOverdueBackNotice(SystemNoticeVo
                .build("红包退还通知",String.format("<p>您有一笔红包已过期退还</p>" +
                                "<p>退还金额：%s元</p>" +
                                "<p>发红包时间：%s</p>",
                        StringHandler.fenToYuan(StringHandler.getString(modifyAmount)),
                        DateUtil.getDate(redRecord.getRawAddTime(),"yyyy-MM-dd HH:mm:ss")),
                        redRecord.getUserId()));
    }

    public Map<String, Object> redRecords(String redId, String uid) {
        RedRecordCash redRecordResult = redPacketMapper.getRedRecordCashById(StringHandler.getLong(redId));
        if (StringHandler.isEmpty(redRecordResult)) {
            Logger.error("红包信息异常："+redId);
            SystemError.wrapBs("400","红包不存在");
        }
        Integer status = redRecordResult.getRedStatus();// 红包状态
        Integer type = redRecordResult.getType();
        Long amount = redRecordResult.getAmount();
        int size = redRecordResult.getSize();
        Long userId = redRecordResult.getUserId();
        LoginInfo user = loginService.infoByUid(StringHandler.getString(userId));
        // 红包信息
        Map<String, Object> redMap = new HashMap<>();
        redMap.put("alias", McodeHandler.to32Radix(userId));
        redMap.put("payChannel", redRecordResult.payChannel);
        redMap.put("avatarUrl", StringHandler.isEmpty(user.getAvatarUrl())? DEFAULT_IMG:user.getAvatarUrl());
        redMap.put("nickName", user.getNickName());
        redMap.put("remark",redRecordResult.getContent());
        redMap.put("userId", userId+"");
        redMap.put("content", redRecordResult.getContent());
        redMap.put("status", status+"");
        if(PayEnum.RedPackageType.GroupNormal.getCode().equals(String.valueOf(type))) {// 求和
            redMap.put("amount",StringHandler.getDouble(StringHandler.fenToYuan(String.valueOf(amount)))*size + "");
        }else {
            redMap.put("amount", StringHandler.getDouble(StringHandler.fenToYuan(String.valueOf(amount))) + "");
        }
        redMap.put("allNum", size);
        redMap.put("type", type+"");
        redMap.put("createTime", com.ys.utils.base.j2se.DateUtil.getDate(redRecordResult.getRawAddTime(),"yyyy-MM-dd HH:mm:ss"));
        // 红包列表
        List<LoginInfo> userList = redPacketMapper.userRedRecordList(redId);
        // 抢红包手气最佳用户id
        String luckUser = "0";
        String finishTimes = "";// 分
        if (PayEnum.RedPackageStatus.Complete.getCode().equals(String.valueOf(status))) {
            int times = DateUtil.geTimes(redRecordResult.getRawAddTime(), redRecordResult.getRawUpdateTime());
            finishTimes = times > 0 ? String.valueOf(times) : "0";
        }
        if (PayEnum.RedPackageStatus.Complete.getCode().equals(String.valueOf(status)) &&
                (PayEnum.RedPackageType.GroupLuck.getCode().equals(String.valueOf(type)) ||
                        PayEnum.RedPackageType.GroupPersonal.getCode().equals(String.valueOf(type)))) {
            luckUser = luckUser(userList);
        }
        String finalLuckUser = luckUser;
        AtomicReference<String> receivedAmount = new AtomicReference<>("0.00");
        List<Map<String,Object>> list = userList.stream().map(x->{
            if(x.getId().equals(uid)){
                receivedAmount.set(StringHandler.fenToYuan(x.getAmount()));
            }
            Map<String,Object> map = new HashMap<>();
            map.put("alias", McodeHandler.to32Radix(StringHandler.getLong(x.getId())));
            map.put("amount", StringHandler.getDouble(StringHandler.fenToYuan(x.getAmount())) + "");
            map.put("avatarUrl",StringHandler.isNotEmpty(x.getAvatarUrl())?x.getAvatarUrl():DEFAULT_IMG);
            map.put("nickName",x.getNickName());
            map.put("createDateTime",DateUtil.format(x.getRedTime(), DateUtil.FormatType.DAYTIME));
            map.put("remark", x.getId().equals(finalLuckUser) ?"手气最佳":"");
            return map;
        }).collect(Collectors.toList());
        redMap.put("receivers", list);
        redMap.put("finishTimes", finishTimes);
        redMap.put("receivedAmount",receivedAmount);
        redMap.put("receiverNum",userList.size());
        return redMap;
    }

    public int redNum(long uid){
        return redPacketMapper.redNum(uid);
    }
}
